package priv.utrix.micro.filter;

import cn.hutool.core.util.StrUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.web.savedrequest.Enumerator;
import org.springframework.web.filter.OncePerRequestFilter;
import priv.utrix.micro.annotation.CustomizeInvalidAnnotation;
import priv.utrix.micro.constant.AuthConstants;
import priv.utrix.micro.dubbo.RedisTokenDubbo;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;

/**
 * Web过滤器
 *
 * @author utrix
 * @date 2020/11/5
 */
@Slf4j
@Order(1)
@Configuration
@CustomizeInvalidAnnotation
@WebFilter(urlPatterns = "/**", filterName = "authorizeFilter")
public class AuthorizeFilter extends OncePerRequestFilter {

    @DubboReference
    RedisTokenDubbo tokenDubbo;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String jwt = request.getHeader(AuthConstants.JWT_TOKEN_HEADER);
        if (StrUtil.isBlank(jwt)) {
            chain.doFilter(request, response);
            return;
        }

        jwt = jwt.replace(AuthConstants.JWT_TOKEN_PREFIX, Strings.EMPTY);
        String token = tokenDubbo.getToken(jwt);

        HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
            /*
             重写的目的是oauth2.0在获取token的时候，把请求头中的jti替换成token
             oauth获取token信息：
                 对象：org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor
                 方法：protected String extractHeaderToken(HttpServletRequest request);
             */
            @Override
            public Enumeration<String> getHeaders(String name) {
                if (!AuthConstants.JWT_TOKEN_HEADER.equalsIgnoreCase(name)) {
                    return super.getHeaders(name);
                }

                Enumeration<String> headers = super.getHeaders(name);
                ArrayList<String> newHeaders = Lists.newArrayList();
                while (headers.hasMoreElements()) {
                    String value = headers.nextElement();
                    if ((value.toLowerCase().startsWith(OAuth2AccessToken.BEARER_TYPE.toLowerCase()))) {
                        value = Joiner.on(StrUtil.EMPTY).join(AuthConstants.JWT_TOKEN_PREFIX, token);
                    }
                    newHeaders.add(value);
                }

                return new Enumerator<>(newHeaders);
            }
        };

        chain.doFilter(requestWrapper, response);
    }

}